#!/usr/bin/env python
# -*- coding: utf-8 -*-

import md5
import os, os.path, sys
import time

from cell import Cell, KeyNotFoundError,KeyExistError

import log

#######################################################################

class   Cache(object) :
    SUCCESS  = 200
    IGNORE   = 201
    EXPIRED  = 202
    NOTFOUND = 404
    FAILURE  = 500

    def __init__(self, store_path, n_cells=1) :
        self.store_path = store_path
        self.n_cells = n_cells

        self._cells = []

        self._createCells()
        # __init__()

    def __del__(self) :
        self._dropCells()
        # __del__()

    def _createCells(self) :
        for n in range(self.n_cells) :
            cell_path = os.sep.join((self.store_path, '%04d' % n))
            cell = Cell(cell_path)
            self._cells.append( cell )
        # _create_cells()

    def _dropCells(self) :
        for cell in self._cells :
            del cell
        self._cells = []
        # _drop_cells()

    def makeKey(self, items) :
        if isinstance(items, str) :
            _k = items
        elif isinstance(items, list) or isinstance(items, tuple) :
            _k = '###'.join([str(x) for x in items])
        else :
            raise TypeError
        key = md5.new(_k).hexdigest()
        return key
        # makeKey()

    def mapKey(self, key) :
        try :
            _hash = int(key[:4],16)
        except ValueError:
            _key = md5.new(str(key)).hexdigest()
            _hash = int(_key[:4],16)
        _hash = _hash % self.n_cells

        return _hash
        # mapKey()

    def getCell(self, cell_id) :
        cell = self._cells[ cell_id ]
        return cell
        # getCell()

    def insert(self, key, value, timeout=0) :
        '''
        return STATUS
            200 -- SUCCESS
            201 -- IGNORE
            500 -- FAILURE
        '''
        cell_key = self.makeKey(key)
        cell_id  = self.mapKey(cell_key)
        cell = self.getCell(cell_id)

        try :
            ok = cell.insert(key, value, timeout)
        except KeyExistError :
            status = self.IGNORE
        except :
            status = self.FAILURE
        else :
            status = self.SUCCESS if ok else self.FAILURE
        return status
        # insert()

    def erase(self, key) :
        '''
        return STATUS
            200 -- SUCCESS
            404 -- NOT FOUND
            500 -- FAILURE
        '''
        cell_key = self.makeKey(key)
        cell_id  = self.mapKey(cell_key)
        cell = self.getCell(cell_id)

        try :
            ok = cell.erase(key)
        except KeyNotFoundError :
            status = self.NOTFOUND
        except :
            status = self.FAILURE
        else :
            status = self.SUCCESS if ok else self.FAILURE
        return status
        # erase()

    def lookup(self, key) :
        '''
        return (STATUS, DATA)
            200 -- SUCCESS
            202 -- EXPIRED
            404 -- NOT FOUND
            500 -- FAILURE
        '''
        cell_key = self.makeKey(key)
        cell_id  = self.mapKey(cell_key)
        cell = self.getCell(cell_id)

        data = None
        try :
            data,lifetime = cell.lookup(key)
        except KeyNotFoundError :
            status = self.NOTFOUND
        except :
            status = self.FAILURE
        else :
            status = self.SUCCESS if lifetime == 0 or lifetime > time.time() else self.EXPIRED

        if self.EXPIRED == status :
            # delete EXPIRED record
            try :
                cell.erase(key)
            except :
                pass

        return status,data
        # lookup()

    # class Cache()

#######################################################################

